home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / amiga / uae-0.7.0b2 / src / od-win32 / posixemu.c < prev    next >
C/C++ Source or Header  |  1998-01-20  |  14KB  |  646 lines

  1. /* 
  2.  * UAE - The Un*x Amiga Emulator
  3.  *
  4.  * Win32 interface
  5.  *
  6.  * Copyright 1997 Mathias Ortmann
  7.  */
  8.  
  9. #ifdef __GNUC__
  10. #define __int64 long long
  11. #include "machdep/winstuff.h"
  12. #else
  13. #include <windows.h>
  14. #include <ddraw.h>
  15. #include <stdlib.h>
  16. #include <stdarg.h>
  17. #include <commctrl.h>
  18. #include <commdlg.h>
  19. #include <stdio.h>
  20. #include <fcntl.h>
  21. #include <sys/stat.h>
  22. #include <io.h>
  23. #endif
  24.  
  25. #include "config.h"
  26. #include "sysconfig.h"
  27. #include "sysdeps.h"
  28. #include "options.h"
  29. #include "memory.h"
  30. #include "osdep/win32.h"
  31.  
  32. /* stdioemu, posixemu, mallocemu, and various file system helper routines */
  33. static DWORD lasterror;
  34.  
  35. static int isillegal (unsigned char *str)
  36. {
  37.     unsigned char a = *str, b = str[1], c = str[2];
  38.  
  39.     if (a >= 'a' && a <= 'z')
  40.     a &= ~' ';
  41.     if (b >= 'a' && b <= 'z')
  42.     b &= ~' ';
  43.     if (c >= 'a' && c <= 'z')
  44.     c &= ~' ';
  45.  
  46.     return (a == 'A' && b == 'U' && c == 'X' ||
  47.         a == 'C' && b == 'O' && c == 'N' ||
  48.         a == 'P' && b == 'R' && c == 'N' ||
  49.         a == 'N' && b == 'U' && c == 'L');
  50. }
  51.  
  52. static int checkspace (char *str, char s, char d)
  53. {
  54.     char *ptr = str;
  55.  
  56.     while (*ptr && *ptr == s)
  57.     ptr++;
  58.  
  59.     if (!*ptr || *ptr == '/' || *ptr == '\\') {
  60.     while (str < ptr)
  61.         *(str++) = d;
  62.     return 0;
  63.     }
  64.     return 1;
  65. }
  66.  
  67. /* This is sick and incomplete... in the meantime, I have discovered six new illegal file name formats
  68.  * M$ sucks! */
  69. void fname_atow (char *src, char *dst, int size)
  70. {
  71.     char *lastslash = dst, *strt = dst;
  72.     int i, j;
  73.  
  74.     while (size-- > 0) {
  75.     if (!(*dst = *src++))
  76.         break;
  77.  
  78.     if (*dst == '~' || *dst == '|' || *dst == '*' || *dst == '?') {
  79.         if (size > 2) {
  80.         sprintf (dst, "~%02x", *dst);
  81.         size -= 2;
  82.         dst += 2;
  83.         }
  84.     } else if (*dst == '/') {
  85.         if (checkspace (lastslash, ' ', 0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash)) {
  86.         i = dst - lastslash - 3;
  87.         dst++;
  88.         for (j = i + 1; j--; dst--)
  89.             *dst = dst[-1];
  90.         *(dst++) = 0xa0;
  91.         dst += i;
  92.         size--;
  93.         } else if (*lastslash == '.' && (dst - lastslash == 1 || lastslash[1] == '.' && dst - lastslash == 2) && size) {
  94.         *(dst++) = 0xa0;
  95.         size--;
  96.         }
  97.         *dst = '\\';
  98.         lastslash = dst + 1;
  99.     }
  100.     dst++;
  101.     }
  102.  
  103.     if (checkspace (lastslash, ' ', 0xa0) && (dst - lastslash == 3 || (dst - lastslash > 3 && lastslash[3] == '.')) && isillegal (lastslash) && size > 1) {
  104.     i = dst - lastslash - 3;
  105.     dst++;
  106.     for (j = i + 1; j--; dst--)
  107.         *dst = dst[-1];
  108.     *(dst++) = 0xa0;
  109.     } else if (!strcmp (lastslash, ".") || !strcmp (lastslash, ".."))
  110.     strcat (lastslash, "\xa0");
  111. }
  112.  
  113. int getdiskfreespace (char *name, int *f_blocks, int *f_bavail, int *f_bsize)
  114. {
  115.     char buf1[1024];
  116.     char buf2[1024];
  117.     DWORD SectorsPerCluster;
  118.     DWORD BytesPerSector;
  119.     DWORD NumberOfFreeClusters;
  120.     DWORD TotalNumberOfClusters;
  121.  
  122.     fname_atow (name, buf1, sizeof buf1);
  123.  
  124.     GetFullPathName (buf1, sizeof buf2, buf2, NULL);
  125.  
  126.     buf2[3] = 0;
  127.  
  128.     if (!GetDiskFreeSpace (buf2, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters)) {
  129.     lasterror = GetLastError ();
  130.     return FALSE;
  131.     }
  132.     *f_blocks = TotalNumberOfClusters;
  133.     *f_bavail = NumberOfFreeClusters;
  134.     *f_bsize = SectorsPerCluster * BytesPerSector;
  135.  
  136.     return TRUE;
  137. }
  138.  
  139. /* Translate lasterror to valid AmigaDOS error code
  140.  * The mapping is probably not 100% correct yet */
  141. long dos_errno (void)
  142. {
  143.     int i;
  144.  
  145.     static DWORD errtbl[][2] =
  146.     {
  147.     {ERROR_FILE_NOT_FOUND, 205},    /* 2 */
  148.     {ERROR_PATH_NOT_FOUND, 205},    /* 3 */
  149.     {ERROR_SHARING_VIOLATION, 202},
  150.     {ERROR_ACCESS_DENIED, 223},    /* 5 */
  151.     {ERROR_ARENA_TRASHED, 103},    /* 7 */
  152.     {ERROR_NOT_ENOUGH_MEMORY, 103},        /* 8 */
  153.     {ERROR_INVALID_BLOCK, 219},    /* 9 */
  154.     {ERROR_INVALID_DRIVE, 204},    /* 15 */
  155.     {ERROR_CURRENT_DIRECTORY, 214},        /* 16 */
  156.     {ERROR_NO_MORE_FILES, 232},    /* 18 */
  157.     {ERROR_LOCK_VIOLATION, 214},    /* 33 */
  158.     {ERROR_BAD_NETPATH, 204},    /* 53 */
  159.     {ERROR_NETWORK_ACCESS_DENIED, 214},    /* 65 */
  160.     {ERROR_BAD_NET_NAME, 204},    /* 67 */
  161.     {ERROR_FILE_EXISTS, 203},    /* 80 */
  162.     {ERROR_CANNOT_MAKE, 214},    /* 82 */
  163.     {ERROR_FAIL_I24, 223},    /* 83 */
  164.     {ERROR_DRIVE_LOCKED, 202},    /* 108 */
  165.     {ERROR_DISK_FULL, 221},        /* 112 */
  166.     {ERROR_NEGATIVE_SEEK, 219},    /* 131 */
  167.     {ERROR_SEEK_ON_DEVICE, 219},    /* 132 */
  168.     {ERROR_DIR_NOT_EMPTY, 216},    /* 145 */
  169.     {ERROR_ALREADY_EXISTS, 203},    /* 183 */
  170.     {ERROR_FILENAME_EXCED_RANGE, 205},    /* 206 */
  171.     {ERROR_NOT_ENOUGH_QUOTA, 221},    /* 1816 */
  172.     {ERROR_DIRECTORY, 212}};
  173.  
  174.     for (i = sizeof (errtbl) / sizeof (errtbl[0]); i--;) {
  175.     if (errtbl[i][0] == lasterror)
  176.         return errtbl[i][1];
  177.     }
  178.     return 236;
  179. }
  180.  
  181. static DWORD getattr (char *name, LPFILETIME lpft, size_t * size)
  182. {
  183.     HANDLE hFind;
  184.     WIN32_FIND_DATA fd;
  185.  
  186.     if ((hFind = FindFirstFile (name, &fd)) == INVALID_HANDLE_VALUE) {
  187.     lasterror = GetLastError ();
  188.  
  189.     fd.dwFileAttributes = GetFileAttributes (name);
  190.  
  191.     return fd.dwFileAttributes;
  192.     }
  193.     FindClose (hFind);
  194.  
  195.     if (lpft)
  196.     *lpft = fd.ftLastWriteTime;
  197.     if (size)
  198.     *size = fd.nFileSizeLow;
  199.  
  200.     return fd.dwFileAttributes;
  201. }
  202.  
  203. int posixemu_access (char *name, int mode)
  204. {
  205.     DWORD attr;
  206.     char buf[1024];
  207.  
  208.     fname_atow (name, buf, sizeof buf - 4);
  209.  
  210.     if ((attr = getattr (buf, NULL, NULL)) == ~0)
  211.     return -1;
  212.  
  213.     if (attr & FILE_ATTRIBUTE_READONLY && (mode & 4)) {
  214.     lasterror = ERROR_ACCESS_DENIED;
  215.     return -1;
  216.     } else
  217.     return 0;
  218. }
  219.  
  220. int posixemu_open (char *name, int oflag, int dummy)
  221. {
  222.     DWORD fileaccess;
  223.     DWORD filecreate;
  224.     char buf[1024];
  225.  
  226.     HANDLE hFile;
  227.  
  228.     switch (oflag & (O_RDONLY | O_WRONLY | O_RDWR)) {
  229.     case O_RDONLY:
  230.     fileaccess = GENERIC_READ;
  231.     break;
  232.     case O_WRONLY:
  233.     fileaccess = GENERIC_WRITE;
  234.     break;
  235.     case O_RDWR:
  236.     fileaccess = GENERIC_READ | GENERIC_WRITE;
  237.     break;
  238.     default:
  239.     return -1;
  240.     }
  241.  
  242.     switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
  243.     case 0:
  244.     case O_EXCL:
  245.     filecreate = OPEN_EXISTING;
  246.     break;
  247.     case O_CREAT:
  248.     filecreate = OPEN_ALWAYS;
  249.     break;
  250.     case O_CREAT | O_EXCL:
  251.     case O_CREAT | O_TRUNC | O_EXCL:
  252.     filecreate = CREATE_NEW;
  253.     break;
  254.     case O_TRUNC:
  255.     case O_TRUNC | O_EXCL:
  256.     filecreate = TRUNCATE_EXISTING;
  257.     break;
  258.     case O_CREAT | O_TRUNC:
  259.     filecreate = CREATE_ALWAYS;
  260.     break;
  261.     }
  262.  
  263.     fname_atow (name, buf, sizeof buf);
  264.  
  265.     if ((hFile = CreateFile (buf,
  266.                  fileaccess,
  267.                  FILE_SHARE_READ | FILE_SHARE_WRITE,
  268.                  NULL,
  269.                  filecreate,
  270.                  FILE_ATTRIBUTE_NORMAL,
  271.                  NULL)) == INVALID_HANDLE_VALUE)
  272.     lasterror = GetLastError ();
  273.  
  274.     return (int) hFile;
  275. }
  276.  
  277. void posixemu_close (int hFile)
  278. {
  279.     CloseHandle ((HANDLE) hFile);
  280. }
  281.  
  282. int w32fopendel (char *name, char *mode, int delflag)
  283. {
  284.     HANDLE hFile;
  285.     hFile = CreateFile (name,
  286.             mode[1] == '+' ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ,
  287.             FILE_SHARE_READ | FILE_SHARE_WRITE,
  288.             NULL,
  289.             OPEN_EXISTING,
  290.             delflag ? FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE : FILE_ATTRIBUTE_NORMAL,
  291.             NULL);
  292.  
  293.     if (hFile == INVALID_HANDLE_VALUE) {
  294.     lasterror = GetLastError ();
  295.     hFile = 0;
  296.     }
  297.     return (int) hFile;
  298. }
  299.  
  300. int stdioemu_fclose (FILE * fd)
  301. {
  302.     if (fd)
  303.     CloseHandle ((HANDLE) fd);
  304.     return 0;
  305. }
  306.  
  307. void *mallocemu_malloc (int size)
  308. {
  309.     return GlobalAlloc (GPTR, size);
  310. }
  311.  
  312. void mallocemu_free (void *ptr)
  313. {
  314.     GlobalFree (ptr);
  315. }
  316.  
  317. static int hextol (char a)
  318. {
  319.     if (a >= '0' && a <= '9')
  320.     return a - '0';
  321.     if (a >= 'a' && a <= 'f')
  322.     return a - 'a' + 10;
  323.     if (a >= 'A' && a <= 'F')
  324.     return a - 'A' + 10;
  325.     return 2;
  326. }
  327.  
  328. /* Win32 file name restrictions suck... */
  329. void fname_wtoa (unsigned char *ptr)
  330. {
  331.     unsigned char *lastslash = ptr;
  332.  
  333.     while (*ptr) {
  334.     if (*ptr == '~') {
  335.         *ptr = hextol (ptr[1]) * 16 + hextol (ptr[2]);
  336.         strcpy (ptr + 1, ptr + 3);
  337.     } else if (*ptr == '\\') {
  338.         if (checkspace (lastslash, ' ', 0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash)) {
  339.         ptr--;
  340.         strcpy (lastslash + 3, lastslash + 4);
  341.         }
  342.         *ptr = '/';
  343.         lastslash = ptr + 1;
  344.     }
  345.     ptr++;
  346.     }
  347.  
  348.     if (checkspace (lastslash, ' ', 0xa0) && ptr - lastslash > 3 && lastslash[3] == 0xa0 && isillegal (lastslash))
  349.     strcpy (lastslash + 3, lastslash + 4);
  350. }
  351.  
  352. DIR {
  353.     WIN32_FIND_DATA finddata;
  354.     HANDLE hDir;
  355.     int getnext;
  356. };
  357.  
  358. DIR *opendir (char *path)
  359. {
  360.     char buf[1024];
  361.     DIR *dir;
  362.  
  363.     if (!(dir = (DIR *) GlobalAlloc (GPTR, sizeof (DIR)))) {
  364.     lasterror = GetLastError ();
  365.     return 0;
  366.     }
  367.     fname_atow (path, buf, sizeof buf - 4);
  368.     strcat (buf, "\\*");
  369.  
  370.     if ((dir->hDir = FindFirstFile (buf, &dir->finddata)) == INVALID_HANDLE_VALUE) {
  371.     lasterror = GetLastError ();
  372.     GlobalFree (dir);
  373.     return 0;
  374.     }
  375.     return dir;
  376. }
  377.  
  378. struct dirent *readdir (DIR * dir)
  379. {
  380.     if (dir->getnext) {
  381.     if (!FindNextFile (dir->hDir, &dir->finddata)) {
  382.         lasterror = GetLastError ();
  383.         return 0;
  384.     }
  385.     }
  386.     dir->getnext = TRUE;
  387.  
  388.     fname_wtoa (dir->finddata.cFileName);
  389.     return (struct dirent *) dir->finddata.cFileName;
  390. }
  391.  
  392. void closedir (DIR * dir)
  393. {
  394.     FindClose (dir->hDir);
  395.     GlobalFree (dir);
  396. }
  397.  
  398. int setfiletime (char *name, unsigned int days, int minute, int tick)
  399. {
  400.     FILETIME LocalFileTime, FileTime;
  401.     HANDLE hFile;
  402.     int success;
  403.     char buf[1024];
  404.  
  405.     fname_atow (name, buf, sizeof buf);
  406.  
  407.     if ((hFile = CreateFile (buf, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
  408.     lasterror = GetLastError ();
  409.     return 0;
  410.     }
  411.     *(__int64 *) & LocalFileTime = (((__int64) (377 * 365 + 91 + days) * (__int64) 1440 + (__int64) minute) * (__int64) (60 * 50) + (__int64) tick) * (__int64) 200000;
  412.  
  413.     if (!LocalFileTimeToFileTime (&LocalFileTime, &FileTime))
  414.     FileTime = LocalFileTime;
  415.  
  416.     if (!(success = SetFileTime (hFile, &FileTime, &FileTime, &FileTime)))
  417.     lasterror = GetLastError ();
  418.     CloseHandle (hFile);
  419.  
  420.     return success;
  421. }
  422.  
  423. int posixemu_read (int hFile, char *ptr, int size)
  424. {
  425.     DWORD actual;
  426.  
  427.     if (!ReadFile ((HANDLE) hFile, ptr, size, &actual, NULL))
  428.     lasterror = GetLastError ();
  429.  
  430.     return actual;
  431. }
  432.  
  433. int posixemu_write (int hFile, char *ptr, int size)
  434. {
  435.     DWORD actual;
  436.  
  437.     if (!WriteFile ((HANDLE) hFile, ptr, size, &actual, NULL))
  438.     lasterror = GetLastError ();
  439.  
  440.     return actual;
  441. }
  442.  
  443. int posixemu_seek (int hFile, int pos, int type)
  444. {
  445.     int result;
  446.  
  447.     switch (type) {
  448.     case SEEK_SET:
  449.     type = FILE_BEGIN;
  450.     break;
  451.     case SEEK_CUR:
  452.     type = FILE_CURRENT;
  453.     break;
  454.     case SEEK_END:
  455.     type = FILE_END;
  456.     }
  457.  
  458.     if ((result = SetFilePointer ((HANDLE) hFile, pos, NULL, type)) == ~0)
  459.     lasterror = GetLastError ();
  460.  
  461.     return result;
  462. }
  463.  
  464. int stdioemu_fread (char *buf, int l1, int l2, FILE * hFile)
  465. {
  466.     return posixemu_read ((int) hFile, buf, l1 * l2);
  467. }
  468.  
  469. int stdioemu_fwrite (char *buf, int l1, int l2, FILE * hFile)
  470. {
  471.     return posixemu_write ((int) hFile, buf, l1 * l2);
  472. }
  473.  
  474. int stdioemu_fseek (FILE * hFile, int pos, int type)
  475. {
  476.     return posixemu_seek ((int) hFile, pos, type);
  477. }
  478.  
  479. int stdioemu_ftell (FILE * hFile)
  480. {
  481.     return SetFilePointer ((HANDLE) hFile, 0, 0, FILE_CURRENT);
  482. }
  483.  
  484. int posixemu_stat (char *name, struct stat *statbuf)
  485. {
  486.     char buf[1024];
  487.     DWORD attr;
  488.     HANDLE hFile;
  489.     FILETIME ft, lft;
  490.  
  491.     fname_atow (name, buf, sizeof buf);
  492.  
  493.     if ((attr = getattr (buf, &ft, &statbuf->st_size)) == ~0) {
  494.     lasterror = GetLastError ();
  495.     return -1;
  496.     } else {
  497.     statbuf->st_mode = (attr & FILE_ATTRIBUTE_READONLY) ? 5 : 0;
  498.     if (attr & FILE_ATTRIBUTE_ARCHIVE)
  499.         statbuf->st_mode |= 0x10;
  500.     if (attr & FILE_ATTRIBUTE_DIRECTORY)
  501.         statbuf->st_mode |= 0x100;
  502.  
  503.     FileTimeToLocalFileTime (&ft, &lft);
  504.     statbuf->st_mtime = (*(__int64 *) & lft - ((__int64) (369 * 365 + 89) * (__int64) (24 * 60 * 60) * (__int64) 10000000)) / (__int64) 10000000;
  505.     }
  506.  
  507.     return 0;
  508. }
  509.  
  510. int posixemu_mkdir (char *name, int mode)
  511. {
  512.     char buf[1024];
  513.  
  514.     fname_atow (name, buf, sizeof buf);
  515.  
  516.     if (CreateDirectory (buf, NULL))
  517.     return 0;
  518.  
  519.     lasterror = GetLastError ();
  520.  
  521.     return -1;
  522. }
  523.  
  524. int posixemu_unlink (char *name)
  525. {
  526.     char buf[1024];
  527.  
  528.     fname_atow (name, buf, sizeof buf);
  529.     if (DeleteFile (buf))
  530.     return 0;
  531.  
  532.     lasterror = GetLastError ();
  533.  
  534.     return -1;
  535. }
  536.  
  537. int posixemu_rmdir (char *name)
  538. {
  539.     char buf[1024];
  540.  
  541.     fname_atow (name, buf, sizeof buf);
  542.     if (RemoveDirectory (buf))
  543.     return 0;
  544.  
  545.     lasterror = GetLastError ();
  546.  
  547.     return -1;
  548. }
  549.  
  550. int posixemu_rename (char *name1, char *name2)
  551. {
  552.     char buf1[1024];
  553.     char buf2[1024];
  554.  
  555.     fname_atow (name1, buf1, sizeof buf1);
  556.     fname_atow (name2, buf2, sizeof buf2);
  557.     if (MoveFile (name1, name2))
  558.     return 0;
  559.  
  560.     lasterror = GetLastError ();
  561.  
  562.     return -1;
  563. }
  564.  
  565. int posixemu_chmod (char *name, int mode)
  566. {
  567.     char buf[1024];
  568.     DWORD attr = FILE_ATTRIBUTE_NORMAL;
  569.  
  570.     fname_atow (name, buf, sizeof buf);
  571.  
  572.     if (mode & 1)
  573.     attr |= FILE_ATTRIBUTE_READONLY;
  574.     if (mode & 0x10)
  575.     attr |= FILE_ATTRIBUTE_ARCHIVE;
  576.  
  577.     if (SetFileAttributes (buf, attr))
  578.     return 1;
  579.  
  580.     lasterror = GetLastError ();
  581.  
  582.     return 0;
  583. }
  584.  
  585. void posixemu_tmpnam (char *name)
  586. {
  587.     char buf[MAX_PATH];
  588.  
  589.     GetTempPath (MAX_PATH, buf);
  590.     GetTempFileName (buf, "uae", 0, name);
  591. }
  592.  
  593. /* pthread Win32 emulation */
  594. void sem_init (HANDLE * event, int manual_reset, int initial_state)
  595. {
  596.     *event = CreateEvent (NULL, manual_reset, initial_state, NULL);
  597. }
  598.  
  599. void sem_wait (HANDLE * event)
  600. {
  601.     WaitForSingleObject (*event, INFINITE);
  602. }
  603.  
  604. void sem_post (HANDLE * event)
  605. {
  606.     SetEvent (*event);
  607. }
  608.  
  609. int sem_trywait (HANDLE * event)
  610. {
  611.     return WaitForSingleObject (*event, 0) == WAIT_OBJECT_0;
  612. }
  613.  
  614. /* Mega-klduge to prevent problems with Watcom's habit of passing
  615.  * arguments in registers... */
  616. static HANDLE thread_sem;
  617. static void *(*thread_startfunc) (void *);
  618. #ifndef __GNUC__
  619. static void * __stdcall thread_starter (void *arg)
  620. #else
  621. static void * thread_starter( void *arg )
  622. #endif
  623. {
  624.     void *(*func) (void *) = thread_startfunc;
  625.     SetEvent (thread_sem);
  626.     return (*func) (arg);
  627. }
  628.  
  629. /* this creates high priority threads by default to speed up the file system (kludge, will be
  630.  * replaced by a set_penguin_priority() routine soon) */
  631. int start_penguin (void *(*f) (void *), void *arg, DWORD * foo)
  632. {
  633.     static int have_event = 0;
  634.     HANDLE hThread;
  635.  
  636.     if (! have_event) {
  637.     thread_sem = CreateEvent (NULL, 0, 0, NULL);
  638.     have_event = 1;
  639.     }
  640.     thread_startfunc = f;
  641.     hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) thread_starter, arg, 0, foo);
  642.     SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST);
  643.     WaitForSingleObject (thread_sem, INFINITE);
  644. }
  645.  
  646.